package com.huiyeji.dynamic.core.bean;

import com.huiyeji.dynamic.core.annotations.*;

import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;

@DynamicBean("class")
public class DynamicClass {

    private static final List<String> INT = Arrays.asList("java.lang.Integer", "int");
    private static final List<String> BOOLEAN = Arrays.asList("java.lang.Boolean", "boolean");
    private static final List<String> DOUBLE = Arrays.asList("java.lang.Double", "double");
    private static final List<String> LONG = Arrays.asList("java.lang.Long", "long");
    private static final List<String> FLOAT = Arrays.asList("java.lang.Float", "float");
    private static final List<String> SHORT = Arrays.asList("java.lang.Short", "short");
    private static final List<String> BYTE = Arrays.asList("java.lang.Byte", "byte");
    private static final List<String> CHAR = Arrays.asList("java.lang.Character", "char");

    @DynamicMethod
    public Class<?> get(String className) throws Exception{
        return Class.forName(className);
    }

    @DynamicMethod
    public Class<?> of(String className) throws Exception{
        return get(className);
    }


    @DynamicMethod
    public Object createObject(String className) throws Exception{
        Class<?> aClass = Class.forName(className);
        Constructor<?> constructor = aClass.getConstructor();
        return constructor.newInstance();
    }

    @DynamicMethod
    public Object createObject(String className, List<Object> params) throws Exception{
        Class<?> aClass = Class.forName(className);
        Object[] array = params.toArray();
        Constructor<?> constructor = getConstructor(aClass, array);
        if (constructor == null){
            throw new RuntimeException("未找到该类对应构造器");
        }
        return constructor.newInstance(array);
    }

    private Constructor<?> getConstructor(Class<?> aClass,Object[] params) throws Exception{
        Constructor<?>[] constructors = aClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            if (isAllInstanceof(constructor,params)){
                return constructor;
            }
        }
        return null;
    }

    private boolean isAllInstanceof(Constructor<?> constructor,Object[] params){
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        if (parameterTypes.length == 0 || params.length != parameterTypes.length){
            return false;
        }
        for (int i = 0; i < params.length; i++) {
            Class<?> aClass = params[i].getClass();
            if (!parameterTypes[i].isAssignableFrom(aClass)){
                if (!isSameBaseType(parameterTypes[i].getName(), aClass.getName())){
                    return false;
                }
            }
        }
        return true;
    }

    private boolean isSameBaseType(String name1, String name2){
        return      INT.contains(name1) && INT.contains(name2)
                || BOOLEAN.contains(name1) && BOOLEAN.contains(name2)
                || DOUBLE.contains(name1) && DOUBLE.contains(name2)
                || LONG.contains(name1) && LONG.contains(name2)
                || FLOAT.contains(name1) && FLOAT.contains(name2)
                || SHORT.contains(name1) && SHORT.contains(name2)
                || BYTE.contains(name1) && BYTE.contains(name2)
                || CHAR.contains(name1) && CHAR.contains(name2);
    }
}
